package org.alvin.bolai;

import io.netty.buffer.ByteBufUtil;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;

/**
 * @author 唐植超
 * @date 2019/12/28
 */
public class ByteUtils {

    /**
     * 将int数值转换为占四个字节的byte数组，本方法适用于(低位在前，高位在后)的顺序。 和bytesToInt（）配套使用
     *
     * @param value 要转换的int值
     * @return byte数组
     */
    public static byte[] intToBytes(int value) { 
        byte[] src = new byte[4];
        src[3] = (byte) ((value >> 24) & 0xFF);
        src[2] = (byte) ((value >> 16) & 0xFF);
        src[1] = (byte) ((value >> 8) & 0xFF);
        src[0] = (byte) (value & 0xFF);
        return src;
    }

    /**
     * 将int数值转换为占四个字节的byte数组，本方法适用于(高位在前，低位在后)的顺序。  和bytesToInt2（）配套使用
     */
    public static byte[] intToBytes2(int value) {
        byte[] src = new byte[4];
        src[0] = (byte) ((value >> 24) & 0xFF);
        src[1] = (byte) ((value >> 16) & 0xFF);
        src[2] = (byte) ((value >> 8) & 0xFF);
        src[3] = (byte) (value & 0xFF);
        return src;
    }

    /**
     * byte数组中取int数值，本方法适用于(低位在前，高位在后)的顺序，和和intToBytes（）配套使用
     *
     * @param src    byte数组
     * @param offset 从数组的第offset位开始
     * @return int数值
     */
    public static int bytesToInt(byte[] src, int offset) {
        int value;
        value = (int) ((src[offset] & 0xFF)
                | ((src[offset + 1] & 0xFF) << 8)
                | ((src[offset + 2] & 0xFF) << 16)
                | ((src[offset + 3] & 0xFF) << 24));
        return value;
    }

    /**
     * byte数组中取int数值，本方法适用于(低位在后，高位在前)的顺序。和intToBytes2（）配套使用
     */
    public static int bytesToInt2(byte[] src, int offset) {
        int value;
        value = (int) (((src[offset] & 0xFF) << 24)
                | ((src[offset + 1] & 0xFF) << 16)
                | ((src[offset + 2] & 0xFF) << 8)
                | (src[offset + 3] & 0xFF));
        return value;
    }

    /*两个字节十六进制转无符号整型*/
    public static int bytes2ToInt(byte[] src) {
        int value;
        value = (int) ((src[0] & 0xFF) | ((src[0 + 1] & 0xFF) << 8));
        return value;
    }

    public static int bytes2ToIntHL(byte[] src) {
        int value;
        value = ((src[1] & 0xFF) | ((src[0] & 0xFF) << 8));
        return value;
    }

    /*两个字节十六进制转无符号整型*/
    public static int bytes2ToIntHL(byte[] src, int offset) {
        int value;
        value = (int) ((src[offset + 1] & 0xFF) | ((src[offset] & 0xFF) << 8));
        return value;
    }

    public static int bytes2ToInt(byte[] src, int offset) {
        int value;
        value = (int) ((src[offset] & 0xFF) | ((src[offset + 1] & 0xFF) << 8));
        return value;
    }

    /*无符号整型转两个字节十六进制 高低位互换*/
    public static byte[] intToByte2LH(int src) throws Exception {
        if (src > 65535) throw new Exception("data overflow");
        String intString = String.format("%04x", src);
        return ByteUtils.byteChange(ByteBufUtil.decodeHexDump(intString));
    }

    /*无符号整型转两个字节十六进制 不互换*/
    public static byte[] intToByte2(int src) throws Exception {
        if (src > 65535) throw new Exception("data overflow");
        String intString = String.format("%04x", src);
        return ByteBufUtil.decodeHexDump(intString);
    }

    /**
     * 将int数值转换为占四个字节的byte数组，本方法适用于(低位在前，高位在后)的顺序。
     *
     * @param value 要转换的int值
     * @return byte数组
     */
    public static byte[] intToBytesLH(int value) {
        byte[] byte_src = new byte[4];
        byte_src[3] = (byte) ((value & 0xFF000000) >> 24);
        byte_src[2] = (byte) ((value & 0x00FF0000) >> 16);
        byte_src[1] = (byte) ((value & 0x0000FF00) >> 8);
        byte_src[0] = (byte) ((value & 0x000000FF));
        return byte_src;
    }

    /**
     * byte数组中取int数值，本方法适用于(低位在前，高位在后)的顺序。
     *
     * @param ary    byte数组
     * @param offset 从数组的第offset位开始
     * @return int数值
     */
    public static int bytesToIntLH(byte[] ary, int offset) {
        int value;
        value = (int) ((ary[offset] & 0xFF)
                | ((ary[offset + 1] << 8) & 0xFF00)
                | ((ary[offset + 2] << 16) & 0xFF0000)
                | ((ary[offset + 3] << 24) & 0xFF000000));
        return value;
    }


    /**
     * 浮点转换为字节
     *
     * @param f
     * @return
     */
    public static byte[] float2byte(float f) {

        // 把float转换为byte[]
        int fbit = Float.floatToIntBits(f);
        String hex = Integer.toHexString(fbit);
        //如果是0，返回4个字节，1个float占4个字节
        if (f == 0) {
            return new byte[4];
        } else {
            return ByteBufUtil.decodeHexDump(hex);
        }

//        byte[] b = new byte[4];
//        for (int i = 0; i < 4; i++) {
//            b[i] = (byte) (fbit >> (24 - i * 8));
//        }
//
//        // 翻转数组
//        int len = b.length;
//        // 建立一个与源数组元素类型相同的数组
//        byte[] dest = new byte[len];
//        // 为了防止修改源数组，将源数组拷贝一份副本
//        System.arraycopy(b, 0, dest, 0, len);
//        byte temp;
//        // 将顺位第i个与倒数第i个交换
//        for (int i = 0; i < len / 2; ++i) {
//            temp = dest[i];
//            dest[i] = dest[len - i - 1];
//            dest[len - i - 1] = temp;
//        }

//        return dest;

    }

    /**
     * 字节转换为浮点
     *
     * @param b     字节（至少4个字节）
     * @param index 开始位置
     * @return
     */
    public static float byte2float(byte[] b, int index) {
        int l;
        l = b[index + 0];
        l &= 0xff;
        l |= ((long) b[index + 1] << 8);
        l &= 0xffff;
        l |= ((long) b[index + 2] << 16);
        l &= 0xffffff;
        l |= ((long) b[index + 3] << 24);


        return Float.intBitsToFloat(l);
    }

    // Convert the 32-bit binary into the decimal
    private static float GetFloat32(String Binary) {
        int intBits = Integer.parseInt(Binary, 2);
        float myFloat = Float.intBitsToFloat(intBits);
        return myFloat;
    }

    // Get 32-bit IEEE 754 format of the decimal value
    private static String GetBinary32(float value) {
        int intBits = Float.floatToIntBits(value);
        String binary = Integer.toBinaryString(intBits);
        return binary;
    }

    //高低位互换的方法
    public static byte[] byteChange(byte[] bytes) {
        byte[] result = new byte[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            result[i] = bytes[bytes.length - i - 1];
        }
        return result;
    }


    public static byte[] MD5(String algorithm) throws Exception {
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        messageDigest.update(algorithm.getBytes("UTF-8"));
        return messageDigest.digest();
    }

    /**
     * 字符转字节，长度不够补0
     *
     * @param data
     * @param len
     * @return
     */
    public static byte[] string2ByteExtZero(String data, int len) throws UnsupportedEncodingException {
        byte[] dataBuff = ByteBufUtil.decodeHexDump(data);
        if (dataBuff.length >= len) {
            return dataBuff;
        }
        byte[] resultBuff = new byte[len];
        for (int i = 0; i < len; i++) {
            if (i < dataBuff.length) {
                resultBuff[i] = dataBuff[i];
            } else {
                resultBuff[i] = 0;
            }
        }
        return resultBuff;
    }

    /**
     * 字符转字节，长度不够补0
     *
     * @param data
     * @param len
     * @return
     */
    public static byte[] string2ByteExtZeroHL(String data, int len) throws UnsupportedEncodingException {
        byte[] dataBuff = ByteBufUtil.decodeHexDump(data);
        dataBuff = byteChange(dataBuff);
        if (dataBuff.length >= len) {
            return dataBuff;
        }
        byte[] resultBuff = new byte[len];
        for (int i = 0; i < len; i++) {
            if (i < dataBuff.length) {
                resultBuff[i] = dataBuff[i];
            } else {
                resultBuff[i] = 0;
            }
        }
        return resultBuff;
    }

    /**
     * 字符转字节，长度不够补0
     *
     * @param data
     * @param len
     * @return
     */
    public static byte[] string2ByteExtZero(String data, int len, boolean isASCII) throws UnsupportedEncodingException {
        if (!isASCII) {
            return null;
        }
        byte[] dataBuff = data.getBytes();
        if (dataBuff.length >= len) {
            return dataBuff;
        }
        byte[] resultBuff = new byte[len];
        for (int i = 0; i < len; i++) {
            if (i < dataBuff.length) {
                resultBuff[i] = dataBuff[i];
            } else {
                resultBuff[i] = 0;
            }
        }
        return resultBuff;
    }


    /**
     * 压缩BCD码解码
     *
     * @param bytes
     * @return
     */
    public static String bcd2Str(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            int h = ((bytes[i] & 0xff) >> 4) + 48;
            sb.append((char) h);
            int l = (bytes[i] & 0x0f) + 48;
            sb.append((char) l);
        }
        return sb.toString();
    }

    /**
     * 压缩BCD码编码
     *
     * @param str
     * @return
     */
    public static byte[] str2Bcd(String str) {

        if (str.length() % 2 != 0) {
            return null;
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        char[] cs = str.toCharArray();
        for (int i = 0; i < cs.length; i += 2) {
            int high = cs[i] - 48;
            int low = cs[i + 1] - 48;
            baos.write(high << 4 | low);
        }
        return baos.toByteArray();
    }

    /**
     * 高1位
     *
     * @param value
     * @return
     */
    public static int high1Bit(byte value) {
        return (value & 0x80) >> 7;
    }

    /**
     * 低7位
     *
     * @param value
     * @return
     */
    public static int low7Bit(byte value) {
        return value & 0x7F;
    }


    /**
     * 将byte转为16进制
     *
     * @param bytes
     * @return
     */
    public static String byte2Hex(byte[] bytes) {
        StringBuffer stringBuffer = new StringBuffer();
        String temp = null;
        for (int i = 0; i < bytes.length; i++) {
            temp = Integer.toHexString(bytes[i] & 0xFF);
            if (temp.length() == 1) {
                // 1得到一位的进行补0操作
                stringBuffer.append("0");
            }
            stringBuffer.append(temp);
        }
        return stringBuffer.toString();
    }

    public static String zeroStr(String str) {

        int index = 0;

        for (int i = 0; i < str.length(); i++) {
            int value = Integer.parseInt(String.valueOf(str.charAt(i)));
            if (value > 0) {
                index = i;
                break;
            }
        }
        str = str.substring(index, str.length());
        return str;
    }


    public static int byteArrayToInt(byte[] bytes) {
        int res = 0;
        for (int i = 0; i < bytes.length; i++) {
            res += (bytes[i] & 0xff) << i * 8;
        }
        return res;
    }


    /**
     * 十六进制数据转换为十进制字符串数
     *
     * @param hex
     * @return
     */
    public static String hexToDec(String hex) {
        BigInteger data = new BigInteger(hex, 16);
        return data.toString(10);
    }


    public static String stringToHexString(String s) {
        String str = "";
        for (int i = 0; i < s.length(); i++) {
            int ch = s.charAt(i);
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }
        return str;
    }

    public static String hexStringToString(String s) {
        if (s == null || s.equals("")) {
            return null;
        }
        s = s.replace(" ", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(
                        s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            s = new String(baKeyword, "gbk");
            new String();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return s;
    }


    public static byte[] hexString2Bytes(String src) {

        int l = src.length() / 2;

        byte[] ret = new byte[l];

        for (int i = 0; i < l; i++) {

            ret[i] = (byte) Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();

        }

        return ret;

    }

    public static byte[] str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
            // sb.append(' ');
        }
        return bs;
    }

    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }

    /**
     * 求字节数组的校验和
     *
     * @param buff 需要求校验和的字节数组
     * @return 校验和
     */
    public static int sumCheck(byte[] buff) {
        int sum = 0;
        for (byte b : buff) {
            sum += b & 0xFF;
        }
        return sum & 0xFF;
    }



    /**
     * 将short转为低字节在前，高字节在后的byte数组(小端)
     *
     * @param s short
     * @return byte[]
     */
    public static byte[] shortToByteLittle(short s) {
        byte[] b = new byte[2];
        b[0] = (byte) (s & 0xff);
        b[1] = (byte) (s >> 8 & 0xff);
        return b;
    }


    //b为传入的字节，i为第几位（范围0-7），如要获取bit0，则i=0 ''一个byte占8位 ( bit0-bti7
    public static int getBit(byte b,int i) {
        int bit = (int)((b>>i) & 0x1);
        return bit;
    }

    //b为传入的字节，start是起始位，length是长度，如要获取bit0-bit4的值，则start为0，length为5 一个byte占8位 ( bit0-bti7
    public static int getBits(byte b,int start,int length) {
        int bit = (int)((b>>start)&(0xFF>>(8-length)));
        return bit;
    }



    /**
     * hex字符串转byte数组
     * @param inHex 待转换的Hex字符串
     * @return  转换后的byte数组结果
     */
    public static byte[] hexToByteArray(String inHex){
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1){
            //奇数
            hexlen++;
            result = new byte[(hexlen/2)];
            inHex="0"+inHex;
        }else {
            //偶数
            result = new byte[(hexlen/2)];
        }
        int j=0;
        for (int i = 0; i < hexlen; i+=2){
            result[j]=hexToByte(inHex.substring(i,i+2));
            j++;
        }
        return result;
    }

    /**
     * Hex字符串转byte
     * @param inHex 待转换的Hex字符串
     * @return  转换后的byte
     */
    public static byte hexToByte(String inHex){
        return (byte)Integer.parseInt(inHex,16);
    }


    public static void main(String[] args) {
        //精度丢失
//        int value = Double.valueOf().intValue();
//        byte[] buff = ByteUtils.intToBytesNew(value);
//        double sharpRate = 0.6234F;
//        System.out.println(BigDecimal.valueOf(sharpRate).multiply(BigDecimal.valueOf(100000)).intValue());
//        System.out.println(0.6234 * 100000);

//        byte[] newBuff = hexString2Bytes("83f30000");
//          value = ByteUtils.bytesToIntNew(newBuff);
//        System.out.println(value);

//        String str="2a424743522c4f4d2c3836353737313035333334313833302c51302c333936230a";
//        String str="FFFF2a424743522c4f4d2c3836353737313035333334313833302c51302c333936230a";
//
//        System.out.println(hexStringToString(str));
//
//        byte [] tno= {0x00,0x01,0x00,0x12,0x20,0x07,0x00};
//        String code = ByteUtils.bcd2Str(tno);
//        System.out.println(code);
//
//        byte [] tno= {0x41,0x34,0x30,0x33,0x4E,0x32,0x31 ,0x37};
//        String version = new String(tno);
//        System.out.println(version);
//        System.out.println(stringToHexString(ss));
    }

//    //BCD转string
//    public static String bcd2Str(byte[] bytes) {
//        StringBuffer temp = new StringBuffer(bytes.length * 2);
//        for (int i = 0; i <bytes.length; i++) {
//            temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
//            temp.append((byte) (bytes[i] & 0x0f));
//        }
//        return temp.toString().substring(0, 1).equalsIgnoreCase("0") ? temp
//                .toString().substring(1) : temp.toString();
//
//    }
//
//    // string转BCD
//    public static byte[] str2Bcd(String asc) {
//        int len = asc.length()
//        int mod = len % 2;
//        if (mod != 0) {
//            asc = "0" + asc;
//            len = asc.length();
//        }
//        byte abt[] = new byte[len];
//        if (len >= 2) {
//            len = len / 2;
//        }
//        byte bbt[] = new byte[len];
//        abt = asc.getBytes();
//        int j, k;
//        for (int p = 0; p < asc.length() / 2; p++) {
//            if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
//                j = abt[2 * p] - '0';
//            } else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
//                j = abt[2 * p] - 'a' + 0x0a;
//            } else {
//                j = abt[2 * p] - 'A' + 0x0a;
//            }
//            if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
//                k = abt[2 * p + 1] - '0';
//            } else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
//                k = abt[2 * p + 1] - 'a' + 0x0a;
//            } else {
//                k = abt[2 * p + 1] - 'A' + 0x0a;
//            }
//            int a = (j << 4) + k;
//            byte b = (byte) a;
//            bbt[p] = b;
//        }
//        return bbt;
//    }
}
